<script type="text/javascript">
	// Initialize variables from Flask context
	let step = {{ step|tojson }};
	let step_size = {{ sec_per_step|tojson }} * 1000; // Convert to milliseconds
	let zoom = {{ zoom|tojson }};
	if (zoom <= 0) zoom = document.documentElement.clientWidth / 4400;

	let tile_width = 32;
	let movement_speed = {{ play_speed|tojson }};
	let execute_count_max = tile_width / movement_speed;
	let execute_count = execute_count_max;
	let all_movement = {{ all_movement|tojson }};

	let datetime_options = { weekday: "long", year: "numeric", month: "long", day: "numeric" };
	let start_datetime = new Date(Date.parse({{ start_datetime|tojson }}));

	// Persona related variables
	let persona_names = {{ persona_init_pos|tojson }};
	var spawn_tile_loc = {};
	for (var key in persona_names) {
		spawn_tile_loc[key] = persona_names[key];
	}

	var personas = {};
	var pronunciatios = {};
	let anims_direction;
	let pre_anims_direction;
	let pre_anims_direction_dict = {};

	let movement_target = {};

	let finished = false;
	let paused = false;

	// Phaser configuration
	const config = {
		type: Phaser.AUTO,
		// width: 4480,
		// height: 3200,
        width: document.documentElement.clientWidth / zoom,
        height: document.documentElement.clientHeight / zoom,
		parent: "game-container",
        mode: Phaser.Scale.FIT,
		pixelArt: true,
		physics: {
			default: "arcade",
			arcade: {
				gravity: { y: 0 }
			}
		},
		scene: {
			preload: preload,
			create: create,
			update: update
		},
		scale: {
			zoom: zoom
		}
	};

	// Create Phaser game instance
	const game = new Phaser.Game(config);
	let cursors;
	let player;

	// Preload function
	function preload() {
		this.load.crossOrigin = "";

		// Load images
		this.load.image("blocks_1", "static/assets/village/tilemap/blocks_1.png");
		this.load.image("walls", "static/assets/village/tilemap/Room_Builder_32x32.png");
		this.load.image("interiors_pt1", "static/assets/village/tilemap/interiors_pt1.png");
		this.load.image("interiors_pt2", "static/assets/village/tilemap/interiors_pt2.png");
		this.load.image("interiors_pt3", "static/assets/village/tilemap/interiors_pt3.png");
		this.load.image("interiors_pt4", "static/assets/village/tilemap/interiors_pt4.png");
		this.load.image("interiors_pt5", "static/assets/village/tilemap/interiors_pt5.png");
		this.load.image("CuteRPG_Field_B", "static/assets/village/tilemap/CuteRPG_Field_B.png");
		this.load.image("CuteRPG_Field_C", "static/assets/village/tilemap/CuteRPG_Field_C.png");
		this.load.image("CuteRPG_Harbor_C", "static/assets/village/tilemap/CuteRPG_Harbor_C.png");
		this.load.image("CuteRPG_Village_B", "static/assets/village/tilemap/CuteRPG_Village_B.png");
		this.load.image("CuteRPG_Forest_B", "static/assets/village/tilemap/CuteRPG_Forest_B.png");
		this.load.image("CuteRPG_Desert_C", "static/assets/village/tilemap/CuteRPG_Desert_C.png");
		this.load.image("CuteRPG_Mountains_B", "static/assets/village/tilemap/CuteRPG_Mountains_B.png");
		this.load.image("CuteRPG_Desert_B", "static/assets/village/tilemap/CuteRPG_Desert_B.png");
		this.load.image("CuteRPG_Forest_C", "static/assets/village/tilemap/CuteRPG_Forest_C.png");

		// Load tilemap JSON
		this.load.tilemapTiledJSON("map", "static/assets/village/tilemap/tilemap.json");

		this.load.atlas("atlas", "static/assets/village/agents/伊莎贝拉/texture.png", filename="static/assets/village/agents/sprite.json");

		// Load persona atlases
		for (var p in persona_names) {
			image_static = "static/assets/village/agents/" + p + "/texture.png";
			this.load.atlas(p, image_static, filename="static/assets/village/agents/sprite.json");
		}
	}

	// Create function
	function create() {
		const map = this.make.tilemap({ key: "map" });

		// Add tilesets and layers
		const collisions = map.addTilesetImage("blocks", "blocks_1");
		const walls = map.addTilesetImage("Room_Builder_32x32", "walls");
		const interiors_pt1 = map.addTilesetImage("interiors_pt1", "interiors_pt1");
		const interiors_pt2 = map.addTilesetImage("interiors_pt2", "interiors_pt2");
		const interiors_pt3 = map.addTilesetImage("interiors_pt3", "interiors_pt3");
		const interiors_pt4 = map.addTilesetImage("interiors_pt4", "interiors_pt4");
		const interiors_pt5 = map.addTilesetImage("interiors_pt5", "interiors_pt5");
		const CuteRPG_Field_B = map.addTilesetImage("CuteRPG_Field_B", "CuteRPG_Field_B");
		const CuteRPG_Field_C = map.addTilesetImage("CuteRPG_Field_C", "CuteRPG_Field_C");
		const CuteRPG_Harbor_C = map.addTilesetImage("CuteRPG_Harbor_C", "CuteRPG_Harbor_C");
		const CuteRPG_Village_B = map.addTilesetImage("CuteRPG_Village_B", "CuteRPG_Village_B");
		const CuteRPG_Forest_B = map.addTilesetImage("CuteRPG_Forest_B", "CuteRPG_Forest_B");
		const CuteRPG_Desert_C = map.addTilesetImage("CuteRPG_Desert_C", "CuteRPG_Desert_C");
		const CuteRPG_Mountains_B = map.addTilesetImage("CuteRPG_Mountains_B", "CuteRPG_Mountains_B");
		const CuteRPG_Desert_B = map.addTilesetImage("CuteRPG_Desert_B", "CuteRPG_Desert_B");
		const CuteRPG_Forest_C = map.addTilesetImage("CuteRPG_Forest_C", "CuteRPG_Forest_C");

		let tileset_group_1 = [CuteRPG_Field_B, CuteRPG_Field_C, CuteRPG_Harbor_C, CuteRPG_Village_B,
			CuteRPG_Forest_B, CuteRPG_Desert_C, CuteRPG_Mountains_B, CuteRPG_Desert_B, CuteRPG_Forest_C,
			interiors_pt1, interiors_pt2, interiors_pt3, interiors_pt4, interiors_pt5, walls];
		const bottomGroundLayer = map.createLayer("Bottom Ground", tileset_group_1, 0, 0);
		const exteriorGroundLayer = map.createLayer("Exterior Ground", tileset_group_1, 0, 0);
		const exteriorDecorationL1Layer = map.createLayer("Exterior Decoration L1", tileset_group_1, 0, 0);
		const exteriorDecorationL2Layer = map.createLayer("Exterior Decoration L2", tileset_group_1, 0, 0);
		const interiorGroundLayer = map.createLayer("Interior Ground", tileset_group_1, 0, 0);
		const wallLayer = map.createLayer("Wall", [CuteRPG_Field_C, walls], 0, 0);
		const interiorFurnitureL1Layer = map.createLayer("Interior Furniture L1", tileset_group_1, 0, 0);
		const interiorFurnitureL2Layer = map.createLayer("Interior Furniture L2 ", tileset_group_1, 0, 0);
		const foregroundL1Layer = map.createLayer("Foreground L1", tileset_group_1, 0, 0);
		const foregroundL2Layer = map.createLayer("Foreground L2", tileset_group_1, 0, 0);

		const collisionsLayer = map.createLayer("Collisions", collisions, 0, 0);

		collisionsLayer.setCollisionByProperty({ collide: true });

		collisionsLayer.setDepth(-1);
		foregroundL1Layer.setDepth(2);
		foregroundL2Layer.setDepth(2);

		const canvas = game.canvas;
		canvas.addEventListener("wheel", (event) => {
			event.stopPropagation();
		}, { passive: false, capture: true });

		function add_text(game, x, y, text, background) {
			res = game.add.text(
				x,
				y,
				text,
				{
					font: "24px 黑体",
					fontWeight: "normal",
					fill: "#000000",
					backgroundColor: background,
					padding: { x: 20, y: 4},
					align: "left",
					wordWrap: { width: 1200/zoom, useAdvancedWrap: true },
				}
			);

			res.setDepth(10);
			res.alpha = 0.8;
			res.setScrollFactor(0);

			return res;
		}

		posX = 20;
		posY = 20;

		// Add button: play, pause ...
		buttonPlay = add_text(this, posX, posY, "[运行]", "#ffffcc");
		buttonPlay.setInteractive();
		posX += buttonPlay.width + 10;

		buttonPause = add_text(this, posX, posY, " 暂停 ", "#ffffcc");
		buttonPause.setInteractive();
		posX += buttonPause.width + 10;

		buttonShowConversation = add_text(this, posX, posY, "[显示对话]", "#ffffcc");
		buttonShowConversation.setInteractive();
		posX += buttonShowConversation.width + 10;

		buttonHideConversation = add_text(this, posX, posY, " 隐藏对话 ", "#ffffcc");
		buttonHideConversation.setInteractive();
		posX += buttonHideConversation.width + 10;

		// Show current time
		currentTime = add_text(this, posX, posY, "", "#ccffcc");

		// Show conversation content
		textConversation = add_text(this, 20, posY + currentTime.height + 10, " —— ", "#ccffcc");

		// Setup camera
		player = this.physics.add.sprite(2440, 500, "atlas", "down").setSize(30, 40).setOffset(0, 0);
		player.setDepth(-1);
		const camera = this.cameras.main;
		camera.startFollow(player);
		camera.setBounds(0, 0, map.widthInPixels, map.heightInPixels);
		cursors = this.input.keyboard.createCursorKeys();

		// Setup personas
		// We start by creating the game sprite objects.
		for (let i=0; i<Object.keys(spawn_tile_loc).length; i++) {
			let persona_name = Object.keys(spawn_tile_loc)[i];
			let start_pos = [spawn_tile_loc[persona_name][0] * tile_width + tile_width / 2, spawn_tile_loc[persona_name][1] * tile_width + tile_width];
			let new_sprite = this.physics.add.sprite(start_pos[0], start_pos[1], persona_name, "down").setSize(30, 40).setOffset(0, 0);
			// Scale up the sprite
			new_sprite.displayWidth = 40;
			new_sprite.scaleY = new_sprite.scaleX;

			// Here, we are creating the persona and its pronunciatio sprites.
			personas[persona_name] = new_sprite;
			pronunciatios[persona_name] = this.add.text(
				new_sprite.body.x - 15,
				new_sprite.body.y - 15 - 25,
				"",
				{
					font: "18px monospace",
					fill: "#000000",
					backgroundColor: "#ffffcc",
					padding: { x: 4, y: 4},
					border:"solid",
					borderRadius:"10px"
				}
			).setDepth(3);
			pronunciatios[persona_name].alpha = 0.7;
		}

		// Create animations
		const anims = this.anims;
		for (let i = 0; i < Object.keys(persona_names).length; i++) {
			let persona_name = Object.keys(persona_names)[i];
			let left_walk_name = persona_name + "-left-walk";
			let right_walk_name = persona_name + "-right-walk";
			let down_walk_name = persona_name + "-down-walk";
			let up_walk_name = persona_name + "-up-walk";

			frameRate = 4;
			if (movement_speed > 1) frameRate = 8;

			anims.create({
				key: left_walk_name,
				frames: anims.generateFrameNames(persona_name, { prefix: "left-walk.", start: 0, end: 3, zeroPad: 3 }),
				frameRate: frameRate,
				repeat: -1
			});

			anims.create({
				key: right_walk_name,
				frames: anims.generateFrameNames(persona_name, { prefix: "right-walk.", start: 0, end: 3, zeroPad: 3 }),
				frameRate: frameRate,
				repeat: -1
			});

			anims.create({
				key: down_walk_name,
				frames: anims.generateFrameNames(persona_name, { prefix: "down-walk.", start: 0, end: 3, zeroPad: 3 }),
				frameRate: frameRate,
				repeat: -1
			});

			anims.create({
				key: up_walk_name,
				frames: anims.generateFrameNames(persona_name, { prefix: "up-walk.", start: 0, end: 3, zeroPad: 3 }),
				frameRate: frameRate,
				repeat: -1
			});
		}
	}

	// Update function
	function update(time, delta) {
		// Setup play and pause button
		buttonPlay.on("pointerdown", function() {
			if (finished) return;
			buttonPlay.text = "[运行]";
			buttonPause.text = " 暂停 ";
			paused = false;
		});

		buttonPause.on("pointerdown", function() {
			if (finished) return;
			buttonPlay.text = " 运行 ";
			buttonPause.text = "[暂停]";
			paused = true;
		});

		buttonShowConversation.on("pointerdown", function() {
			buttonShowConversation.text = "[显示对话]";
			buttonHideConversation.text = " 隐藏对话 ";
			textConversation.setVisible(true);
		});

		buttonHideConversation.on("pointerdown", function() {
			buttonShowConversation.text = " 显示对话 ";
			buttonHideConversation.text = "[隐藏对话]";
			textConversation.setVisible(false);
		});

		// Move camera
		const camera_speed = 400;
		player.body.setVelocity(0);
		if (cursors.left.isDown) {
			player.body.setVelocityX(-camera_speed);
		}
		if (cursors.right.isDown) {
			player.body.setVelocityX(camera_speed);
		}
		if (cursors.up.isDown) {
			player.body.setVelocityY(-camera_speed);
		}
		if (cursors.down.isDown) {
			player.body.setVelocityY(camera_speed);
		}

		let curr_focused_persona = document.getElementById("temp_focus").textContent;
		if (curr_focused_persona != "") {
			player.body.x = personas[curr_focused_persona].body.x;
			player.body.y = personas[curr_focused_persona].body.y;
			document.getElementById("temp_focus").innerHTML = "";
		}

		if (finished || paused) {
			return;
		}

		curr_datetime = new Date(start_datetime.getTime());
		curr_year = curr_datetime.getFullYear().toString().padStart(4, "0");
		curr_month = (curr_datetime.getMonth() + 1).toString().padStart(2, "0");
		curr_day = curr_datetime.getDate().toString().padStart(2, "0");
		curr_hour = curr_datetime.getHours().toString().padStart(2, "0");
		curr_minute = curr_datetime.getMinutes().toString().padStart(2, "0");
		conversation_key = `${curr_year}${curr_month}${curr_day}-${curr_hour}:${curr_minute}`;
		conversation_key_text = all_movement["conversation"][conversation_key];
		if (conversation_key_text && conversation_key_text != "") {
			textConversation.setText(`\n${conversation_key} 对话记录：\n` + conversation_key_text);
		}

		// Moving personas
		for (let i = 0; i < Object.keys(personas).length; i++) {
			let curr_persona_name = Object.keys(personas)[i];
			let curr_persona = personas[curr_persona_name];
			let curr_pronunciatio = pronunciatios[Object.keys(personas)[i]];

			if (step in all_movement) {
				if (curr_persona_name.replace("_", " ") in all_movement[step]) {
					if (execute_count == execute_count_max) {
						let curr_x = all_movement[step][curr_persona_name.replace("_", " ")]["movement"][0];
						let curr_y = all_movement[step][curr_persona_name.replace("_", " ")]["movement"][1];
						movement_target[curr_persona_name] = [curr_x * tile_width, curr_y * tile_width];

						let action = all_movement[step][curr_persona_name.replace("_", " ")]["action"];

						let act = action;
						act = act.length > 25 ? act.substring(0, 20)+"..." : act;
						pronunciatios[curr_persona_name].setText(curr_persona_name + ": " + act);

						// Updating the status of each personas
						document.getElementById("agent_desc__"+curr_persona_name).innerHTML = all_movement["description"][curr_persona_name]["currently"];
						document.getElementById("current_action__"+curr_persona_name).innerHTML = action;
						document.getElementById("target_address__"+curr_persona_name).innerHTML = all_movement[step][curr_persona_name.replace("_", " ")]["location"];
					}

					if (execute_count > 0) {
						if (curr_persona.body.x < movement_target[curr_persona_name][0]) {
							curr_persona.body.x += movement_speed;
							anims_direction = "r";
							pre_anims_direction = "r";
							pre_anims_direction_dict[curr_persona_name] = "r";
						} else if (curr_persona.body.x > movement_target[curr_persona_name][0]) {
							curr_persona.body.x -= movement_speed;
							anims_direction = "l";
							pre_anims_direction = "l";
							pre_anims_direction_dict[curr_persona_name] = "l";
						} else if (curr_persona.body.y < movement_target[curr_persona_name][1]) {
							curr_persona.body.y += movement_speed;
							anims_direction = "d";
							pre_anims_direction = "d";
							pre_anims_direction_dict[curr_persona_name] = "d";
						} else if (curr_persona.body.y > movement_target[curr_persona_name][1]) {
							curr_persona.body.y -= movement_speed;
							anims_direction = "u";
							pre_anims_direction = "u";
							pre_anims_direction_dict[curr_persona_name] = "u";
						} else {
							anims_direction = "";
						}

						curr_pronunciatio.x = curr_persona.body.x - 15;
						curr_pronunciatio.y = curr_persona.body.y - 15 - 25;

						let left_walk_name = curr_persona_name + "-left-walk";
						let right_walk_name = curr_persona_name + "-right-walk";
						let down_walk_name = curr_persona_name + "-down-walk";
						let up_walk_name = curr_persona_name + "-up-walk";

						if (anims_direction == "l") {
							curr_persona.anims.play(left_walk_name, true);
						} else if (anims_direction == "r") {
							curr_persona.anims.play(right_walk_name, true);
						} else if (anims_direction == "u") {
							curr_persona.anims.play(up_walk_name, true);
						} else if (anims_direction == "d") {
							curr_persona.anims.play(down_walk_name, true);
						}
					}
				}
			} else {
				if (pre_anims_direction_dict[curr_persona_name] == "l") curr_persona.setTexture(curr_persona_name, "left");
				else if (pre_anims_direction_dict[curr_persona_name] == "r") curr_persona.setTexture(curr_persona_name, "right");
				else if (pre_anims_direction_dict[curr_persona_name] == "u") curr_persona.setTexture(curr_persona_name, "up");
				else if (pre_anims_direction_dict[curr_persona_name] == "d") curr_persona.setTexture(curr_persona_name, "down");
				curr_persona.anims.stop();

				finished = true;
				buttonPlay.text = "[回放结束]";
				buttonPause.setVisible(false);
			}
		}

		if (execute_count == 0) {
			for (let i = 0; i < Object.keys(personas).length; i++) {
				let curr_persona_name = Object.keys(personas)[i];
				let curr_persona = personas[curr_persona_name];
				curr_persona.body.x = movement_target[curr_persona_name][0];
				curr_persona.body.y = movement_target[curr_persona_name][1];
			}
			execute_count = execute_count_max + 1;
			step = step + 1;

			start_datetime = new Date(start_datetime.getTime() + step_size);
			currentTime.setText(start_datetime.toLocaleTimeString("zh-CN", datetime_options));
		}

		execute_count -= 1;
	}
</script>
